#pragma once

/**
  *	An MBNodeIndexWithLabelIndex object capsules a node index and the corresponding
  * label index that refers to the label that is used to label the node.
  */
class MBNodeIndexWithLabelIndex
{
public:
	/**
	  *	Constructs a new MBNodeIndexWithLabelIndex object consisting of a
	  * node index and a label index
	  *
	  * @param nodeIndex index that refers to a particular node
	  * @param labelIndex index that refers to a particular label
	  */
	MBNodeIndexWithLabelIndex( const int &nodeIndex, const int &labelIndex ) :
		mNodeIndex( nodeIndex ),
		mLabelIndex( labelIndex ) {};

	/**
	  *	Compares the current MBNodeIndexWithLabelIndex object and the passed
	  * one and returns true, if the current one is smaller than the passed
	  * one, false otherwise. At first the node indexes are compared, then the
	  * label indexes.
	  *
	  * @param compareIndices MBNodeIndexWithLabelIndex object to be compared with the current one
	  * @return true if the current MBNodeIndexWithLabelIndex object is smaller than the passed one, false otherwise.
	  */
	bool operator<( const MBNodeIndexWithLabelIndex &compareIndices ) const
	{
		// Compare
		if (mNodeIndex < compareIndices.mNodeIndex)
		{
			return true;
		}
		else if (mNodeIndex > compareIndices.mNodeIndex)
		{
			return false;
		}
		else
		{
			if (mLabelIndex < compareIndices.mLabelIndex)
			{
				return true;
			}

			return false;
		}
	}

	/** Index referring to a particular node */
	int mNodeIndex;
	/** Index referring to a particular label */
	int mLabelIndex;
};

/**
  *	An MBNodeIndicesWithLabelIndices object capsules two (node, index) pairs.
  */
class MBNodeIndicesWithLabelIndices
{
public:
	/**
	  *	Constructs a new MBNodeIndicesWithLabelIndices with the given
	  * parameters
	  *
	  * @param firstNodeIndex index of the first node
	  * @param secondNodeIndex index of the second node
	  * @param firstLabelIndex index of the first label
	  * @param secondLabelIndex index of the second label
	  */
	MBNodeIndicesWithLabelIndices(
		const int &firstNodeIndex,
		const int &secondNodeIndex,
		const int &firstLabelIndex,
		const int &secondLabelIndex ) :
			mFirstNodeIndex( firstNodeIndex ),
			mSecondNodeIndex( secondNodeIndex ),
			mFirstLabelIndex( firstLabelIndex ),
			mSecondLabelIndex( secondLabelIndex ) {};
	
	/**
	  *	Compares this MBNodeIndicesWithLabelIndices object with the given and
	  * returns true if this one is smaller than the given one.
	  *
	  * @param compareIndices MBNodeIndicesWithLabelIndices object to be compared with this one
	  * @return true if this MBNodeIndicesWithLabelIndices object is smaller than the given one
	  */
	bool operator<( const MBNodeIndicesWithLabelIndices &compareIndices ) const
	{
		int node_indices[] = { mFirstNodeIndex, mSecondNodeIndex };
		int label_indices[] = { mFirstLabelIndex, mSecondLabelIndex };

		int other_node_indices[] = { compareIndices.mFirstNodeIndex, compareIndices.mSecondNodeIndex };
		int other_label_indices[] = { compareIndices.mFirstLabelIndex, compareIndices.mSecondLabelIndex };

		int helper;

		// Sort
		if (node_indices[0] > node_indices[1])
		{
			helper = node_indices[0];
			node_indices[0] = node_indices[1];
			node_indices[1] = helper;
		}

		if (label_indices[0] > label_indices[1])
		{
			helper = label_indices[0];
			label_indices[0] = label_indices[1];
			label_indices[1] = helper;
		}

		if (other_node_indices[0] > other_node_indices[1])
		{
			helper = other_node_indices[0];
			other_node_indices[0] = other_node_indices[1];
			other_node_indices[1] = helper;
		}

		if (other_label_indices[0] > other_label_indices[1])
		{
			helper = other_label_indices[0];
			other_label_indices[0] = other_label_indices[1];
			other_label_indices[1] = helper;
		}

		// Compare
		if (node_indices[0] < other_node_indices[0])
		{
			return true;
		}
		else if (node_indices[0] > other_node_indices[0])
		{
			return false;
		}
		else
		{
			if (node_indices[1] < other_node_indices[1])
			{
				return true;
			}
			else if (node_indices[1] > other_node_indices[1])
			{
				return false;
			}
			else
			{
				if (label_indices[0] < other_label_indices[0])
				{
					return true;
				}
				else if (label_indices[0] > other_label_indices[0])
				{
					return false;
				}
				else
				{
					if (label_indices[1] < other_label_indices[1])
					{
						return true;
					}

					return false;
				}
			}
		}
	}

	/** Index referring to the first node */
	int mFirstNodeIndex;
	/** Index referring to the second node */
	int mSecondNodeIndex;

	/** Index referring to the first label */
	int mFirstLabelIndex;
	/** Index referring to the second label */
	int mSecondLabelIndex;
};